<?php
namespace Handler;

use Core\CommandProtocol;
use Core\TbRedis;
use Helper\Log;

class Commander
{

    //redis连接句柄
    protected $redis;

    //client列表
    protected $client;

    /**
     * 构造函数
     */
    public function __construct()
    {
        try {
            //创建客户端连接内存表
            $this->client = new  \Swoole\table(1024);
            $this->client->column('fd', \Swoole\table::TYPE_INT, 8);            //连接fd
            $this->client->column('command', \Swoole\table::TYPE_STRING, 128);
            $this->client->column('fromIP', \Swoole\table::TYPE_STRING, 64);
            $this->client->column('deviceID', \Swoole\table::TYPE_STRING, 64);
            $this->client->create();

            $this->command_protocol=new CommandProtocol();

        } catch (Exception $e) {
            echo $e->getMesasge();
        }

    }

    /**
     * 服务器关闭函数
     * @param $serv
     */
    public function onShutdown( $serv ) {}

    /**
     * 任务启动回调函数
     * @param $serv
     * @param $task_id
     * @param $from_id
     * @param $data
     */
    public function onTask($serv, $task_id, $from_id, $data ) {}


    /**
     * 任务完成函数
     * @param $serv
     * @param $task_id
     * @param $data
     */
    public function onFinish($serv, $task_id, $data) {}

    /**
     * 主进程启动回调方法
     * @param  Swoole\Server $serv    swoole对象
     */
    public function onStart($serv)
    {
        echo "command websocket server is running! \n";

        $redis = TbRedis::init('cmdwebscketinit');// new Redis();
        foreach ($redis->keys('wscmd.*') as $cmdky) {
            $redis->del($cmdky);
        }

    }


    public function onManagerStart($serv)
    {
        $handler = $this;

        //命令推送进程
        (new \swoole_process(function ($worker) use ($serv, $handler) {

            while (true) {
                while (true) {
                    try {
                        $redis = TbRedis::init('cmdwebscket');// new Redis();
//                        $redis->connect();
                        Log::print('redis connect successful');
                        break;
                    } catch (\RedisException $e) {
                        Log::print("redis connect fail", $e->getCode());
                        sleep(5);
                    }
                }

                try {
                    while (true) {
                        $data = json_decode($redis->brPop('result', 0)[1], true);

                        if(isset($data['deviceID']) && !empty($data['deviceID']) ){
                            foreach ($handler->client as $r) {
                                foreach ($redis->smembers('wscmd.'.$r['fd']) as $cmdky) { //当前链接的所有命令集合
                                    $fdcmd=json_decode($cmdky,true);
                                    if ($serv->exist($r['fd']) && trim($data['deviceID']) == trim($fdcmd['deviceID'])){
                                        if ($data['wsfd']==$r['fd'] && $fdcmd['command'] && ($data['command'] == 'multi' || strtolower(trim($data['command'])) == strtolower(trim($fdcmd['command'])))){
                                            if($data['type']<>'send') {
                                                echo "----- {$fdcmd['deviceID']}==>{$data['command']} ----- \n ";
                                                var_dump($data['msg']);
                                                echoMsg("\n".$r['fromIP']." : ".json_encode($data,JSON_UNESCAPED_UNICODE).date('Y-m-d H:i:s',time()),$redis,true,'cmdredis','commander');
//                                                $redis->srem('wscmd.'.$r['fd'], $cmdky);
                                            }

                                            $serv->push($r['fd'], json_encode($data,JSON_UNESCAPED_UNICODE));
                                        }
                                        elseif (($data['type']=='update'&& $fdcmd['command']=='getupdatastat')||($data['type']=='geterro' &&  $fdcmd['command']=='geterro')){
                                            //升级过程和状态广播通知&& $data['command'] == 'setupdate'
                                            //10 升级请求成功-1 升级请求失败11，连接服务器12，升级中 1'成功',2'失败',3'校验错误'
                                            $serv->push($r['fd'], json_encode($data,JSON_UNESCAPED_UNICODE));
//                                            var_dump($data);
                                        }
                                        elseif ($data['type']=='gettbstatus' &&  $fdcmd['command']=='getdevicestatus'){
                                            $serv->push($r['fd'], json_encode($data,JSON_UNESCAPED_UNICODE));
echo "publish {$data['deviceID']} gettbstatus \n";
                                        }
                                        elseif ($data['type']=='gettbstatus' &&  $fdcmd['command']=='gettemprtable'){
                                            $nwdata=[];
                                            $nwdata['orssi']=$data['temperature'];
                                            $nwdata['RSSI']=$data['temperature2'];
                                            $nwdata['deviceID']=$data['deviceID'];
                                            $nwdata['batt']=$data['battery'];
                                            $nwdata['time']=substr($data['returntime'],-9);
                                            $serv->push($r['fd'], json_encode($nwdata,JSON_UNESCAPED_UNICODE));

                                        }
                                    }

                                }
                            }
                        }else{
                            echo "\n 无效返回 \n";
                            var_dump($data);
                        }
                    }
                }
                catch (\RedisException $e) {
                    Log::print("redis connect error", $e->getCode());
                } finally {
                    Log::print($e->getMessage(), $e->getCode());
                }
            }
        },false))->start();


        //设备状态推送进程
        ( new \Swoole\Process(function ($process) use($serv) {
            while (true) {
                //连接redis
                while (true) {
                    try {

                        $theRedis =TbRedis::init("tbcommderstatus");
                        break;
                    } catch (\RedisException $e) {
                        Log::print('redis connect fail', $e->getCode(), $e->getLine());
                        sleep(2);
                    }
                }

                while (true) {
                    $theRedis->psubscribe([getDbNum() . REDIS_TB_STATUS_ALL], function ($redis, $chan, $chanName, $data) use ($serv) {
                        $data = json_decode($data, true);
                        foreach ($this->client as $r) {
                                if ($serv->exist($r['fd']) ){
                                    $sdata=array('deviceID' => $data['deviceid'],'data'=>$data);
                                    $tbserver='config';
                                    if($chanName== getDbNum() . REDIS_TB_STATUS_CONFIG){
                                        $tbserver='config';//命令服务器
                                        $sdata['cfgstatus']  = $data['status'];
                                    }
                                    elseif($chanName== getDbNum() . REDIS_TB_STATUS_SERVER){
                                        $tbserver='data';//数据服务器
                                        $sdata['datastatus']  = $data['status'];
                                    }
                                    
                                    if (trim($r['command']) == 'TbStatus' || (trim($r['command']) == 'TbStatus' && trim($r['deviceID']) == trim($data['deviceid']))){
                                    	$serv->push($r['fd'], json_encode(array('type'=> 'Status', 'data' => $sdata),JSON_UNESCAPED_UNICODE));
                                    }
                                }

                        }
                    });
                    }
                }

            }, false,false))->start();


    }

    /**
     * worker进程启动回调方法
     * @param  Swoole\Server $serv    swoole对象
     * @param  int $worker_id         worker进程id号
     */
    public function onWorkerStart($serv, $worker_id)
    {
        //连接redis
        while (true) {
            try {
                $this->redis[$serv->worker_id] =TbRedis::init('cmdwebscketwkr.'.$serv->worker_id);//new Redis();
                break;
            } catch (\PDOException $e) {;

            }
        }
    }

    /**
     * 连接回调方法
     * @param  Swoole\Server $serv    swoole对象
     * @param  int $req               连接句柄编号
     */
    public function onOpen($serv, $req)
    {
        $this->client->set($req->fd, array('fd' => $req->fd,'fromIP'=>$req->server['remote_addr'].":".$req->server['remote_port']));
    }

    /**
     * 接收数据回调方法
     * @param  Swoole\Server $serv    swoole对象
     * @param  int $frame             连接句柄编号
     */
    public function onMessage($serv, $frame)
    {
        $reids=$this->redis[$serv->worker_id];
        $data = json_decode($frame->data, true);
        if ($data['type'] == 'command') {
            $data['wsfd'] = $frame->fd;
            $data['time'] =date('Y-m-d H:i:s',time());

            if (isset($data['command']) && $data['command'] && $data['deviceid']) {
                $reids->sadd('wscmd.'.$frame->fd,json_encode(array('deviceID' => $data['deviceid'],'wsfd'=>$data['wsfd'],'command' =>$data['command'],'time'=> $data['time'])));//加入到当前链接的命令集合序列中

                if($data['command']=='getupdatastat')
                {
                    $arr = array(
                        'type'     => 'send',
                        'msg'      => '正在获取升级状态中',
                        'deviceID' => $data['deviceid'],
                        'wsfd'     => $data['wsfd'],
                        'token'    => 0,
                        'command'=>$data['command'],
                        'before'   => '',
                        'time'     => 0,
                    );
                    $reids->lPush('result', json_encode($arr));
                }else{
                    //echo "---cmd start--- \n";
                    echoMsg("\n".$this->client->get($frame->fd,'fromIP')." : ".json_encode($data,JSON_UNESCAPED_UNICODE),$reids,true,'cmdredis','commander');

                    dump('>>>>>>>>cmd start');
                    if (in_array($data['command'], ['setWifiChannel', 'getWifiChannel', 'setWifiSSID', 'getWifiSSID'])) {
                        $ability = json_decode($reids->hGet($data['deviceid'], 'ablity'), true);
                        dump($ability);
                        if (!empty($ability['ability']['multi'])) {
                            $data['data']['multi'] = $ability['ability']['multi'] == '支持多设备' ? true : false;
                        } else {
                            $data['data']['multi'] = false;
                        }
                        dump($ability['ability']['multi']);
                    }

                    //$data['command'] = 'getWifiChannel';
                    dump($data);
                    dump('cmd end<<<<<<<<<<<<<<<<<<<<');
                    $retredis= $reids->lPush('command', json_encode($data));
                    //echo "---cmd end--- \n";
                }

                $this->client->set($frame->fd, array('deviceID' => $data['deviceid'],'command' =>$data['type']));
            }

        }elseif($data['type'] == 'Status') {
            $result = $reids->keys('DZ*');
            $list = array();
            foreach ($result as $r) {
                if (! strpos($r, ".") ) {
                    $info = $reids->hGetAll($r);
                    if (isset($info['fd']) && $info['fd'] > 0 && isset($info['status']) && isset($info['deviceinfo']) && isset($info['cfgstatus']))
                        $list[] = array('deviceID' => $info['mac'], 'datastatus' => $info['status'], 'cfgstatus' => $info['cfgstatus'],'deviceinfo'=>$info['deviceinfo'],'data'=>$info);
                }
            }
            $this->client->set($frame->fd, array('command' =>'TbStatus'));
            $serv->push($frame->fd, json_encode(array('type'=> 'StatusList', 'data' => $list)));

        }
        if (isset($data['deviceid']) && $data['deviceid'])
            $this->client->set($frame->fd, array('deviceID' => $data['deviceid']));
    }

    /**
     * 关闭回调方法
     * @param  Swoole\Server $serv    swoole对象
     * @param  int $fd                连接句柄编号
     */
    public function onClose($serv, $fd, $reactorId)
    {
        $this->client->del($fd);
    }

    public function onWorkerStop($serv, $worker_id) {}

    public function onManagerStop($serv) { }

}